import { AddTagAttachmentCommand, AttachmentViewerCommand } from "../command/attach.command"
import { CloseModalCommand } from "../command/modal.command"
import { FocusOnPinInsideCommand } from "../command/navigate.command"
import { PreviewPinCommand } from "../command/pin.command"
import {
  CloseTagCommand,
  OpenTagCommand,
  PreviewTagCommand,
  SaveTagAppearanceCommand,
  SelectTagCommand,
  TagsToggleCommand,
  ToggleTagToolEditorCommand
} from "../command/tags.command"
import { ToggleToolCommand } from "../command/tool.command"
import keyConst from "../constant/key.const"
import AttachmentsData from "../data/AttachmentsData"
import MattertagsData from "../data/MattertagsData"
import SettingsData from "../data/SettingsData"
import SweepData from "../data/SweepData"
import TagsViewData from "../data/TagsViewData"
import ViewmodeData from "../data/ViewmodeData"
import assetTypeEnum from "../enum/assetType.enum"
import attachmentEnum from "../enum/attachment.enum"
import pinTypeEnum from "../enum/pinType.enum"
import { TagDescriptionChunkType } from "../enum/tagChunkType.enum"
import toolEnum, { ToolsList } from "../enum/tool.enum"
import transitionTypeEnum from "../enum/transitionType.enum"
import TextureLoader from "../loader/TextureLoader"
import A from "../math/62679"
import { PinClosedMessage, PinDeselectMessage, PinOpenedMessage, PinSelectedMessage, PinUpdatedMessage } from "../message/pin.message"
import { ToolAssetClosedMessage, ToolAssetOpenedMessage } from "../message/tool.message"
import Module from "./Module"
import PinsModule from "./PinsModule"
export default class TagsModule extends Module {
  activated: boolean
  registered: boolean
  activeBindings: any[]
  updatePerSettings: any
  settingsData: any
  pinRenderer: any
  togglePinAssetEditor: any
  viewData: any
  onCloseTag: any
  tagsWereChanged: any
  onOpenTagViewChanged: any
  onDeselectTag: any
  onPreviewTag: any
  engine: any
  onSelectTag: any
  onOpenTag: any
  saveTagAppearance: any
  tagsData: any
  tagsToolToggled: any
  attachmentsData: any
  sweepData: any
  viewmodeData: any
  maskTexture: any
  backgroundTexture: any
  constructor() {
    super(...arguments),
      (this.name = "tags-module"),
      (this.activated = !1),
      (this.registered = !1),
      (this.activeBindings = []),
      (this.updatePerSettings = () => {
        const e = this.settingsData.tryGetProperty(keyConst.rule.features.mattertags, !1),
          t = !this.in360View()
        this.pinRenderer.setPinTypeVisible(pinTypeEnum.MATTERTAG, t && e)
      }),
      (this.togglePinAssetEditor = async e => {
        e.opened
          ? this.viewData.setTagsToolState(toolEnum.EDITING)
          : this.viewData.tagsToolState === toolEnum.EDITING && this.viewData.setTagsToolState(toolEnum.VIEWING)
      }),
      (this.onCloseTag = async () => {
        this.closeTag()
      }),
      (this.tagsWereChanged = () => {
        this.viewData.updateViewData()
      }),
      (this.onOpenTagViewChanged = () => {
        const e = this.viewData.openTagView
        e && this.updateTag(e)
      }),
      (this.onDeselectTag = e => {
        e.pinType === pinTypeEnum.MATTERTAG && this.closeTag()
      }),
      (this.onPreviewTag = async e => {
        const t = this.viewData.getTagView(e.id)
        t && this.engine.commandBinder.issueCommand(new PreviewPinCommand(t, pinTypeEnum.MATTERTAG))
      }),
      (this.onSelectTag = async e => {
        const { viewData: t, engine: i, log: n, pinRenderer: s } = this,
          { id: r, transition: o } = e,
          a = t.getTagView(r)
        if (a) {
          await i.commandBinder.issueCommand(new ToggleToolCommand(ToolsList.TAGS, !0, !1)),
            s.hideSelectedMesh(),
            await i.commandBinder.issueCommand(new FocusOnPinInsideCommand({ pinPosition: a, transition: o })),
            s.showSelectedMesh(pinTypeEnum.MATTERTAG, a.id),
            i.broadcast(new PinSelectedMessage(a, pinTypeEnum.MATTERTAG))
          const e = t
            .getEnabledTagViews()
            .values()
            .findIndex(e => e.id === a.id)
          t.setListIndex(e), t.setOpenTagView(a, !0)
        } else n.debug("Cannot select a non-existent tag")
      }),
      (this.onOpenTag = async e => this.openTag(e.id, e.transition, e.attachmentId, e.listIndex)),
      (this.saveTagAppearance = async e => {
        const t = this.tagsData,
          i = this.viewData
        if (t.getTag(e.id)) {
          const t = e.properties
          if (Object.keys(t)) {
            i.updateOpenTagView(t)
            const e = i.openTagView
            e && this.engine.broadcast(new PinUpdatedMessage(e, pinTypeEnum.MATTERTAG))
          }
        } else this.log.debug("Cannot update a non-existent tag")
      }),
      (this.tagsToolToggled = async e => {
        e.opened ? this.activateTool() : this.deactivateTool()
      })
  }
  async init(e, t) {
    const [i, n, a, l, c, h] = await Promise.all([
      t.getModule(PinsModule),
      t.market.waitForData(AttachmentsData),
      t.market.waitForData(MattertagsData),
      t.market.waitForData(SweepData),
      t.market.waitForData(SettingsData),
      t.market.waitForData(ViewmodeData)
    ])
    ;(this.pinRenderer = i.pinRenderer),
      (this.attachmentsData = n),
      (this.tagsData = a),
      (this.sweepData = l),
      (this.settingsData = c),
      (this.viewmodeData = h),
      (this.engine = t),
      (this.maskTexture = TextureLoader("./images/tagmask.png")),
      (this.backgroundTexture = TextureLoader("./images/tagbg.png")),
      (this.viewData = new TagsViewData(this.tagsData, this.attachmentsData, this.backgroundTexture, this.maskTexture)),
      this.bindings.push(
        c.onPropertyChanged(keyConst.rule.features.mattertags, this.updatePerSettings),
        t.commandBinder.addBinding(TagsToggleCommand, this.tagsToolToggled),
        t.commandBinder.addBinding(OpenTagCommand, this.onOpenTag),
        t.commandBinder.addBinding(CloseTagCommand, this.onCloseTag),
        t.commandBinder.addBinding(SelectTagCommand, this.onSelectTag),
        t.commandBinder.addBinding(PreviewTagCommand, this.onPreviewTag),
        t.subscribe(PinDeselectMessage, this.onDeselectTag),
        this.tagsData.onChanged(this.tagsWereChanged)
      ),
      this.createEmbedAttachments(),
      t.market.register(this, TagsViewData, this.viewData),
      this.updatePerSettings(),
      this.displayTags()
  }
  dispose(e) {
    this.deactivateTool(),
      this.bindings.forEach(e => {
        e.cancel()
      }),
      (this.bindings = []),
      (this.activeBindings = []),
      this.pinRenderer.removePinsByType(pinTypeEnum.MATTERTAG),
      this.maskTexture.dispose(),
      this.backgroundTexture.dispose(),
      super.dispose(e)
  }
  activateTool() {
    this.activated ||
      (this.viewData.setTagsToolState(toolEnum.CLOSED),
      this.registered
        ? this.activeBindings.forEach(e => {
            e.renew()
          })
        : this.registerHandlers(),
      (this.activated = !0))
  }
  deactivateTool() {
    if (!this.activated) return
    const { openTagView: e } = this.viewData
    e && this.closeTag(!0),
      this.viewData.setTagsToolState(toolEnum.CLOSED),
      this.activeBindings.forEach(e => {
        e.cancel()
      }),
      (this.activated = !1)
  }
  onUpdate() {}
  registerHandlers() {
    const e = this.engine.commandBinder
    this.activeBindings.push(
      this.viewData.onOpenTagViewChanged(this.onOpenTagViewChanged),
      e.addBinding(SaveTagAppearanceCommand, this.saveTagAppearance),
      e.addBinding(ToggleTagToolEditorCommand, this.togglePinAssetEditor)
    ),
      (this.registered = !0)
  }
  in360View() {
    const e = this.sweepData.currentSweep ? this.sweepData.currentSweep : ""
    return this.viewmodeData.isInside() && this.sweepData.isSweepUnaligned(e)
  }
  async createEmbedAttachments() {
    const e = []
    this.tagsData.iterate(t => {
      e.push(this.createEmbedAttachment(t))
    }),
      Promise.all(e).then(() => this.viewData.updateViewData())
  }
  async createEmbedAttachment(e) {
    if (e.mediaSrc && e.mediaType !== TagDescriptionChunkType.none && e.mediaType !== TagDescriptionChunkType.error) {
      const t = e.mediaType
      this.engine.commandBinder.issueCommand(new AddTagAttachmentCommand(e.sid, attachmentEnum.EXTERNAL, t, e.mediaSrc))
    }
  }
  closeTag(e = !1) {
    const t = this.viewData,
      i = t.openTagView
    i &&
      (this.engine.commandBinder.issueCommand(new AttachmentViewerCommand(!1)),
      this.engine.broadcast(new PinClosedMessage(i.id, pinTypeEnum.MATTERTAG)),
      this.engine.broadcast(new ToolAssetClosedMessage())),
      t.setTagsToolState(toolEnum.IDLE),
      t.setOpenTagView(null),
      e || this.engine.commandBinder.issueCommand(new ToggleToolCommand(ToolsList.TAGS, !1))
  }
  displayTags() {
    this.viewData.getEnabledTagViews().forEach(e => {
      this.updateTag(e)
    })
  }
  updateTag(e) {
    this.pinRenderer.updatePin(e.id, pinTypeEnum.MATTERTAG, e, this.backgroundTexture, this.maskTexture)
  }
  async openTag(e, t, i, n = -1) {
    const { viewData: s, engine: r, log: o, pinRenderer: c } = this
    await r.commandBinder.issueCommand(new ToggleToolCommand(ToolsList.TAGS, !0, !0))
    const d = s.getTagView(e)
    if (d) {
      const o = s.openTagView,
        p = d.id === (null == o ? void 0 : o.id) && s.selectedPreview
      if (!o || o.id !== e || p) {
        if ((r.broadcast(new PinOpenedMessage(d, pinTypeEnum.MATTERTAG, !1)), s.setOpenTagView(d, !1), !p)) {
          const e = null !== t ? t : transitionTypeEnum.Instant
          null !== e &&
            (c.hideSelectedMesh(),
            await r.commandBinder.issueCommand(new FocusOnPinInsideCommand({ pinPosition: d, transition: e })),
            c.showSelectedMesh(pinTypeEnum.MATTERTAG, d.id))
        }
        r.broadcast(new ToolAssetOpenedMessage(assetTypeEnum.MATTERTAG, d.id))
      }
      let g = n
      ;-1 === g &&
        (g = s
          .getEnabledTagViews()
          .values()
          .findIndex(t => t.id === e)),
        s.setListIndex(g)
      const f = d.attachments,
        b = i ? f.find(e => e.id === i) : void 0
      if (i && b && A.lV(b)) {
        const e = f.filter(e => A.lV(e))
        await r.commandBinder.issueCommand(new AttachmentViewerCommand(!0, e, i))
      } else r.commandBinder.issueCommand(new CloseModalCommand())
    } else o.debug("Cannot open a non-existent tag")
  }
}
